<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
    
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
  <title>
    cookie的基本概念 |  虎虎生辉
  </title>
  
  <link rel="shortcut icon" href="/blog/favicon.ico" />
  
  
<link rel="stylesheet" href="/blog/css/style.css">

  
<script src="/blog/js/pace.min.js"></script>


  

  

<meta name="generator" content="Hexo 6.0.0"></head>

</html>

<body>
  <div id="app">
    <main class="content">
      <section class="outer">
  <article id="post-Cookiea" class="article article-type-post" itemscope
  itemprop="blogPost" data-scroll-reveal>

  <div class="article-inner">
    
    <header class="article-header">
       
<h1 class="article-title sea-center" style="border-left:0" itemprop="name">
  cookie的基本概念
</h1>
  

    </header>
    

    
    <div class="article-meta">
      <a href="/blog/2019/04/01/Cookiea/" class="article-date">
  <time datetime="2019-04-01T08:24:27.000Z" itemprop="datePublished">2019-04-01</time>
</a>
      
    </div>
    

    
    
    <div class="tocbot"></div>





    

    <div class="article-entry" itemprop="articleBody">
      


      

      
      <h1 id="一个不大不小的问题"><a href="#一个不大不小的问题" class="headerlink" title="一个不大不小的问题"></a>一个不大不小的问题</h1><p>假设服务器有一个接口，通过请求这个接口，可以添加一个管理员</p>
<p>但是，不是任何人都有权力做这种操作的</p>
<p>那么服务器如何知道请求接口的人是有权力的呢？</p>
<p>答案是：只有登录过的管理员才能做这种操作</p>
<p>可问题是，客户端和服务器的传输使用的是http协议，http协议是无状态的，什么叫无状态，就是<strong>服务器不知道这一次请求的人，跟之前登录请求成功的人是不是同一个人</strong></p>
<p><img src="http://mdrs.yuanjin.tech/img/image-20200417161014030.png"></p>
<p><img src="http://mdrs.yuanjin.tech/img/image-20200417161244373.png"></p>
<p>由于http协议的无状态，服务器<strong>忘记</strong>了之前的所有请求，它无法确定这一次请求的客户端，就是之前登录成功的那个客户端。</p>
<blockquote>
<p>你可以把服务器想象成有着严重脸盲症的东哥，他没有办法分清楚跟他说话的人之前做过什么</p>
</blockquote>
<p>于是，服务器想了一个办法</p>
<p>它按照下面的流程来认证客户端的身份</p>
<ol>
<li>客户端登录成功后，服务器会给客户端一个出入证（令牌 token）</li>
<li>后续客户端的每次请求，都必须要附带这个出入证（令牌 token）</li>
</ol>
<p><img src="http://mdrs.yuanjin.tech/img/image-20200417161950450.png"></p>
<p>服务器发扬了认证不认人的优良传统，就可以很轻松的识别身份了。</p>
<p>但是，用户不可能只在一个网站登录，于是客户端会收到来自各个网站的出入证，因此，就要求客户端要有一个类似于卡包的东西，能够具备下面的功能：</p>
<ol>
<li><strong>能够存放多个出入证</strong>。这些出入证来自不同的网站，也可能是一个网站有多个出入证，分别用于出入不同的地方</li>
<li><strong>能够自动出示出入证</strong>。客户端在访问不同的网站时，能够自动的把对应的出入证附带请求发送出去。</li>
<li><strong>正确的出示出入证</strong>。客户端不能将肯德基的出入证发送给麦当劳。</li>
<li><strong>管理出入证的有效期</strong>。客户端要能够自动的发现那些已经过期的出入证，并把它从卡包内移除。</li>
</ol>
<p>能够满足上面所有要求的，就是cookie</p>
<p>cookie类似于一个卡包，专门用于存放各种出入证，并有着一套机制来自动管理这些证件。</p>
<p>卡包内的每一张卡片，称之为<strong>一个cookie</strong>。</p>
<h1 id="cookie的组成"><a href="#cookie的组成" class="headerlink" title="cookie的组成"></a>cookie的组成</h1><p>cookie是浏览器中特有的一个概念，它就像浏览器的专属卡包，管理着各个网站的身份信息。</p>
<p>每个cookie就相当于是属于某个网站的一个卡片，它记录了下面的信息：</p>
<ul>
<li>key：键，比如「身份编号」</li>
<li>value：值，比如袁小进的身份编号「14563D1550F2F76D69ECBF4DD54ABC95」，这有点像卡片的条形码，当然，它可以是任何信息</li>
<li>domain：域，表达这个cookie是属于哪个网站的，比如<code>yuanjin.tech</code>，表示这个cookie是属于<code>yuanjin.tech</code>这个网站的</li>
<li>path：路径，表达这个cookie是属于该网站的哪个基路径的，就好比是同一家公司不同部门会颁发不同的出入证。比如<code>/news</code>，表示这个cookie属于<code>/news</code>这个路径的。（后续详细解释）</li>
<li>secure：是否使用安全传输（后续详细解释）</li>
<li>expire：过期时间，表示该cookie在什么时候过期</li>
</ul>
<p>当浏览器向服务器发送一个请求的时候，它会瞄一眼自己的卡包，看看哪些卡片适合附带捎给服务器</p>
<p>如果一个cookie<strong>同时满足</strong>以下条件，则这个cookie会被附带到请求中</p>
<ul>
<li>cookie没有过期</li>
<li>cookie中的域和这次请求的域是匹配的<ul>
<li>比如cookie中的域是<code>yuanjin.tech</code>，则可以匹配的请求域是<code>yuanjin.tech</code>、<code>www.yuanjin.tech</code>、<code>blogs.yuanjin.tech</code>等等</li>
<li>比如cookie中的域是<code>www.yuanjin.tech</code>，则只能匹配<code>www.yuanjin.tech</code>这样的请求域</li>
<li>cookie是不在乎端口的，只要域匹配即可</li>
</ul>
</li>
<li>cookie中的path和这次请求的path是匹配的<ul>
<li>比如cookie中的path是<code>/news</code>，则可以匹配的请求路径可以是<code>/news</code>、<code>/news/detail</code>、<code>/news/a/b/c</code>等等，但不能匹配<code>/blogs</code></li>
<li>如果cookie的path是<code>/</code>，可以想象，能够匹配所有的路径</li>
</ul>
</li>
<li>验证cookie的安全传输<ul>
<li>如果cookie的secure属性是true，则请求协议必须是<code>https</code>，否则不会发送该cookie</li>
<li>如果cookie的secure属性是false，则请求协议可以是<code>http</code>，也可以是<code>https</code></li>
</ul>
</li>
</ul>
<p>如果一个cookie满足了上述的所有条件，则浏览器会把它自动加入到这次请求中</p>
<p>具体加入的方式是，<strong>浏览器会将符合条件的cookie，自动放置到请求头中</strong>，例如，当我在浏览器中访问百度的时候，它在请求头中附带了下面的cookie：</p>
<p><img src="http://mdrs.yuanjin.tech/img/image-20200417170328584.png"></p>
<p>看到打马赛克的地方了吗？这部分就是通过请求头<code>cookie</code>发送到服务器的，它的格式是<code>键=值; 键=值; 键=值; ...</code>，每一个键值对就是一个符合条件的cookie。</p>
<p><strong>cookie中包含了重要的身份信息，永远不要把你的cookie泄露给别人！！！</strong>否则，他人就拿到了你的证件，有了证件，就具备了为所欲为的可能性。</p>
<h1 id="如何设置cookie"><a href="#如何设置cookie" class="headerlink" title="如何设置cookie"></a>如何设置cookie</h1><p>由于cookie是保存在浏览器端的，同时，很多证件又是服务器颁发的</p>
<p>所以，cookie的设置有两种模式：</p>
<ul>
<li>服务器响应：这种模式是非常普遍的，当服务器决定给客户端颁发一个证件时，它会在响应的消息中包含cookie，浏览器会自动的把cookie保存到卡包中</li>
<li>客户端自行设置：这种模式少见一些，不过也有可能会发生，比如用户关闭了某个广告，并选择了「以后不要再弹出」，此时就可以把这种小信息直接通过浏览器的JS代码保存到cookie中。后续请求服务器时，服务器会看到客户端不想要再次弹出广告的cookie，于是就不会再发送广告过来了。</li>
</ul>
<h2 id="服务器端设置cookie"><a href="#服务器端设置cookie" class="headerlink" title="服务器端设置cookie"></a>服务器端设置cookie</h2><p>服务器可以通过设置响应头，来告诉浏览器应该如何设置cookie</p>
<p>响应头按照下面的格式设置：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">set-cookie:</span> <span class="string">cookie1</span></span><br><span class="line"><span class="attr">set-cookie:</span> <span class="string">cookie2</span></span><br><span class="line"><span class="attr">set-cookie:</span> <span class="string">cookie3</span></span><br><span class="line"><span class="string">...</span></span><br></pre></td></tr></table></figure>

<p>通过这种模式，就可以在一次响应中设置多个cookie了，具体设置多少个cookie，设置什么cookie，根据你的需要自行处理</p>
<p>其中，每个cookie的格式如下：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">键=值; path=?; domain=?; expire=?; max-age=?; secure; httponly</span><br></pre></td></tr></table></figure>

<p>每个cookie除了键值对是必须要设置的，其他的属性都是可选的，并且顺序不限</p>
<p>当这样的响应头到达客户端后，<strong>浏览器会自动的将cookie保存到卡包中，如果卡包中已经存在一模一样的卡片（其他key、path、domain相同），则会自动的覆盖之前的设置</strong>。</p>
<p>下面，依次说明每个属性值：</p>
<ul>
<li><strong>path</strong>：设置cookie的路径。如果不设置，浏览器会将其自动设置为当前请求的路径。比如，浏览器请求的地址是<code>/login</code>，服务器响应了一个<code>set-cookie: a=1</code>，浏览器会将该cookie的path设置为请求的路径<code>/login</code></li>
<li><strong>domain</strong>：设置cookie的域。如果不设置，浏览器会自动将其设置为当前的请求域，比如，浏览器请求的地址是<code>http://www.yuanjin.tech</code>，服务器响应了一个<code>set-cookie: a=1</code>，浏览器会将该cookie的domain设置为请求的域<code>www.yuanjin.tech</code><ul>
<li>这里值得注意的是，如果服务器响应了一个无效的域，浏览器是不认的</li>
<li>什么是无效的域？就是响应的域连根域都不一样。比如，浏览器请求的域是<code>yuanjin.tech</code>，服务器响应的cookie是<code>set-cookie: a=1; domain=baidu.com</code>，这样的域浏览器是不认的。</li>
<li>如果浏览器连这样的情况都允许，就意味着张三的服务器，有权利给用户一个cookie，用于访问李四的服务器，这会造成很多安全性的问题</li>
</ul>
</li>
<li><strong>expire</strong>：设置cookie的过期时间。这里必须是一个有效的GMT时间，即格林威治标准时间字符串，比如<code>Fri, 17 Apr 2020 09:35:59 GMT</code>，表示格林威治时间的<code>2020-04-17 09:35:59</code>，即北京时间的<code>2020-04-17 17:35:59</code>。当客户端的时间达到这个时间点后，会自动销毁该cookie。</li>
<li><strong>max-age</strong>：设置cookie的相对有效期。expire和max-age通常仅设置一个即可。比如设置<code>max-age</code>为<code>1000</code>，浏览器在添加cookie时，会自动设置它的<code>expire</code>为当前时间加上1000秒，作为过期时间。<ul>
<li>如果不设置expire，又没有设置max-age，则表示会话结束后过期。</li>
<li>对于大部分浏览器而言，关闭所有浏览器窗口意味着会话结束。</li>
</ul>
</li>
<li><strong>secure</strong>：设置cookie是否是安全连接。如果设置了该值，则表示该cookie后续只能随着<code>https</code>请求发送。如果不设置，则表示该cookie会随着所有请求发送。</li>
<li><strong>httponly</strong>：设置cookie是否仅能用于传输。如果设置了该值，表示该cookie仅能用于传输，而不允许在客户端通过JS获取，这对防止跨站脚本攻击（XSS）会很有用。 <ul>
<li>关于如何通过JS获取，后续会讲解</li>
<li>关于什么是XSS，不在本文讨论范围</li>
</ul>
</li>
</ul>
<p>下面来一个例子，客户端通过<code>post</code>请求服务器<code>http://yuanjin.tech/login</code>，并在消息体中给予了账号和密码，服务器验证登录成功后，在响应头中加入了以下内容：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">set-cookie: token=123456; path=/; max-age=3600; httponly</span><br></pre></td></tr></table></figure>

<p>当该响应到达浏览器后，浏览器会创建下面的cookie：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">key:</span> <span class="string">token</span></span><br><span class="line"><span class="attr">value:</span> <span class="number">123456</span></span><br><span class="line"><span class="attr">domain:</span> <span class="string">yuanjin.tech</span></span><br><span class="line"><span class="attr">path:</span> <span class="string">/</span></span><br><span class="line"><span class="attr">expire:</span> <span class="number">2020-04-17 18:55:00</span> <span class="comment">#假设当前时间是2020-04-17 17:55:00</span></span><br><span class="line"><span class="attr">secure:</span> <span class="literal">false</span>  <span class="comment">#任何请求都可以附带这个cookie，只要满足其他要求</span></span><br><span class="line"><span class="attr">httponly:</span> <span class="literal">true</span> <span class="comment">#不允许JS获取该cookie</span></span><br></pre></td></tr></table></figure>

<p>于是，随着浏览器后续对服务器的请求，只要满足要求，这个cookie就会被附带到请求头中传给服务器：</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">cookie:</span> <span class="string">token=123456;</span> <span class="string">其他cookie...</span></span><br></pre></td></tr></table></figure>

<p>现在，还剩下最后一个问题，就是如何删除浏览器的一个cookie呢？</p>
<p>如果要删除浏览器的cookie，只需要让服务器响应一个同样的域、同样的路径、同样的key，只是时间过期的cookie即可</p>
<p><strong>所以，删除cookie其实就是修改cookie</strong></p>
<p>下面的响应会让浏览器删除<code>token</code></p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">cookie:</span> <span class="string">token=;</span> <span class="string">domain=yuanjin.tech;</span> <span class="string">path=/;</span> <span class="string">max-age=-1</span></span><br></pre></td></tr></table></figure>

<p>浏览器按照要求修改了cookie后，会发现cookie已经过期，于是自然就会删除了。</p>
<blockquote>
<p>无论是修改还是删除，都要注意cookie的域和路径，因为完全可能存在域或路径不同，但key相同的cookie</p>
<p>因此无法仅通过key确定是哪一个cookie</p>
</blockquote>
<h2 id="客户端设置cookie"><a href="#客户端设置cookie" class="headerlink" title="客户端设置cookie"></a>客户端设置cookie</h2><p>既然cookie是存放在浏览器端的，所以浏览器向JS公开了接口，让其可以设置cookie</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">document</span>.cookie = <span class="string">&quot;键=值; path=?; domain=?; expire=?; max-age=?; secure&quot;</span>;</span><br></pre></td></tr></table></figure>

<p>可以看出，在客户端设置cookie，和服务器设置cookie的格式一样，只是有下面的不同</p>
<ul>
<li>没有httponly。因为httponly本来就是为了限制在客户端访问的，既然你是在客户端配置，自然失去了限制的意义。</li>
<li>path的默认值。在服务器端设置cookie时，如果没有写path，使用的是请求的path。而在客户端设置cookie时，也许根本没有请求发生。因此，path在客户端设置时的默认值是当前网页的path</li>
<li>domain的默认值。和path同理，客户端设置时的默认值是当前网页的domain</li>
<li>其他：一样</li>
<li>删除cookie：和服务器也一样，修改cookie的过期时间即可</li>
</ul>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>以上，就是cookie原理部分的内容。</p>
<p>如果把它用于登录场景，就是如下的流程：</p>
<p><strong>登录请求</strong></p>
<ol>
<li>浏览器发送请求到服务器，附带账号密码</li>
<li>服务器验证账号密码是否正确，如果不正确，响应错误，如果正确，在响应头中设置cookie，附带登录认证信息（至于登录认证信息是设么样的，如何设计，要考虑哪些问题，就是另一个话题了，可以百度 jwt）</li>
<li>客户端收到cookie，浏览器自动记录下来</li>
</ol>
<p><strong>后续请求</strong></p>
<ol>
<li>浏览器发送请求到服务器，希望添加一个管理员，并将cookie自动附带到请求中</li>
<li>服务器先获取cookie，验证cookie中的信息是否正确，如果不正确，不予以操作，如果正确，完成正常的业务流程</li>
</ol>

      
      <!-- 打赏 -->
      
        <div id="reward-btn">
          打赏
        </div>
        
    </div>
    <footer class="article-footer">
      <a data-url="https://gitee.com/huafu123/blog/2019/04/01/Cookiea/" data-id="ckya9fc0x0009ygf6d3a6c0gu"
        class="article-share-link">分享</a>
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/cookie/" rel="tag">cookie</a></li></ul>

    </footer>

  </div>

  
  
  <nav class="article-nav">
    
      <a href="/blog/2019/05/01/CORSa/" class="article-nav-link">
        <strong class="article-nav-caption">上一篇</strong>
        <div class="article-nav-title">
          
            CORS原理详解
          
        </div>
      </a>
    
    
      <a href="/blog/2019/03/01/JWTa/" class="article-nav-link">
        <strong class="article-nav-caption">下一篇</strong>
        <div class="article-nav-title">JWT原理详解</div>
      </a>
    
  </nav>


  

  
  
<!-- valine评论 -->
<div id="vcomments-box">
    <div id="vcomments">
    </div>
</div>
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src='https://cdn.jsdelivr.net/npm/valine@1.3.10/dist/Valine.min.js'></script>
<script>
    new Valine({
        el: '#vcomments',
        notify: false,
        verify: false,
        app_id: '',
        app_key: '',
        path: window.location.pathname,
        avatar: 'mp',
        placeholder: '给我的文章加点评论吧~',
        recordIP: true
    });
    const infoEle = document.querySelector('#vcomments .info');
    if (infoEle && infoEle.childNodes && infoEle.childNodes.length > 0) {
        infoEle.childNodes.forEach(function (item) {
            item.parentNode.removeChild(item);
        });
    }
</script>
<style>
    #vcomments-box {
        padding: 5px 30px;
    }

    @media screen and (max-width: 800px) {
        #vcomments-box {
            padding: 5px 0px;
        }
    }

    #vcomments-box #vcomments {
        background-color: #fff;
    }

    .v .vlist .vcard .vh {
        padding-right: 20px;
    }

    .v .vlist .vcard {
        padding-left: 10px;
    }
</style>

  

  
  
  

</article>
</section>
      <footer class="footer">
  <div class="outer">
    <ul class="list-inline">
      <li>
        &copy;
        2020-2022
        Huafu Li
      </li>
      <li>
        
          Powered by
        
        
        <a href="https://hexo.io" target="_blank">Hexo</a> Theme <a href="https://github.com/Shen-Yu/hexo-theme-ayer" target="_blank">Ayer</a>
        
      </li>
    </ul>
    <ul class="list-inline">
      <li>
        
        
        <ul class="list-inline">
  <li>PV:<span id="busuanzi_value_page_pv"></span></li>
  <li>UV:<span id="busuanzi_value_site_uv"></span></li>
</ul>
        
      </li>
      <li>
        <!-- cnzz统计 -->
        
        <script type="text/javascript" src='https://s9.cnzz.com/z_stat.php?id=1278069914&amp;web_id=1278069914'></script>
        
      </li>
    </ul>
  </div>
</footer>
    <div class="to_top">
        <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>
      </div>
    </main>
    
    <aside class="sidebar">
      
        <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/blog/"><img src="/blog/hu.png" alt="虎虎生辉"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/blog/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/blog/archives">目录</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/blog/about">关于</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/blog/pictures">相册</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="Search">
        <i class="ri-search-line"></i>
      </a>
      
      
      <a class="nav-item-link" target="_blank" href="/blog/atom.xml" title="RSS Feed">
        <i class="ri-rss-line"></i>
      </a>
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
      </aside>
      <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>请我喝杯咖啡吧~</p>
  <div class="reward-box">
    
    <div class="reward-item">
      <img class="reward-img" src="/blog/./images/alipay.png">
      <span class="reward-type">支付宝</span>
    </div>
    
    
    <div class="reward-item">
      <img class="reward-img" src="/blog/./images/wechat.png">
      <span class="reward-type">微信</span>
    </div>
    
  </div>
</div>
      
<script src="/blog/js/jquery-2.0.3.min.js"></script>


<script src="/blog/js/jquery.justifiedGallery.min.js"></script>


<script src="/blog/js/lazyload.min.js"></script>


<script src="/blog/js/busuanzi-2.3.pure.min.js"></script>


  
<script src="/blog/fancybox/jquery.fancybox.min.js"></script>




  
<script src="/blog/js/tocbot.min.js"></script>

  <script>
    // Tocbot_v4.7.0  http://tscanlin.github.io/tocbot/
    tocbot.init({
      tocSelector: '.tocbot',
      contentSelector: '.article-entry',
      headingSelector: 'h1, h2, h3, h4, h5, h6',
      hasInnerContainers: true,
      scrollSmooth: true,
      positionFixedSelector: '.tocbot',
      positionFixedClass: 'is-position-fixed',
      fixedSidebarOffset: 'auto',
			onClick: (e) => {
      	document.getElementById(e.target.innerText).scrollIntoView()
      	return false;
    	}
    });
  </script>


<script>
  var ayerConfig = {
    mathjax: false
  }
</script>


<script src="/blog/js/ayer.js"></script>


<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css">



<script type="text/javascript" src="https://js.users.51.la/20544303.js"></script>
  
  

  </div>
</body>

</html>